/*
** ############################################################################
**     Project   : osdee - Operative Systems Design for Embedded Envrionments
**     File      : pll.c
**     Revision  ; 1.0
**     Abstract  :
**         PLL operation functions implementation.
**     Processor : MC9S12XEP100CVL
**     Version   : Component 01.042, Driver 01.05, CPU db: 3.00.036
**     Datasheet : MC9S12XEP100 Rev. 1.19 12/2008
**
**     Copyright : 2014 Fernando Rodriguez, Open source with out any responsability.
**     
**     mail      : frr@gmail.com
** ############################################################################
*/

#include "pll.h"


/*
** ===================================================================
**     Functions definition for internal use only.
** ===================================================================
*/

/*
** ===================================================================
**     Method      :  mcal_vPLL_ON(void)
**
**     Description :
**         Turns PLL ON.
** ===================================================================
*/
void mcal_vPLL_ON(void);

/*
** ===================================================================
**     Method      :  mcal_vPLL_OFF(void)
**
**     Description :
**         Turns PLL OFF.
** ===================================================================
*/
void mcal_vPLL_OFF(void);


/*
** ===================================================================
**     Variables for internal use only.
** ===================================================================
*/

/*
** ===================================================================
**     Description :
**         Contains current Clock status
** ===================================================================
*/
UINT16 mcal_mcu_u16ClockGlobalStatus;

/*
** ===================================================================
**     Description :
**         Loss of Lock counter
** ===================================================================
*/
UINT16 mcal_mcu_u16PLL_Loss_of_Lock_Counter;

/*
** ===================================================================
**     Description :
**         Actual Bus frequency value.
** ===================================================================
*/
UINT32 mcal_mcu_u32BusFrequency;


/*
** ===================================================================
**     Functions implementation.
** ===================================================================
*/

/*
** ===================================================================
**     Method      :  Mcu_vPLL_Init(void)
**
**     Description :
**         System clock and PLL initialization.
** ===================================================================
*/
void Mcu_vPLL_Init(void)
{       
  /* Disable PLL */
  mcal_vPLL_OFF();
  //      
  /* Set PLL synthesizer register */
  SYNR_SYNDIV = SYNR_VALUE;         
  /* Set PLL divider register */  
  REFDV_REFDIV = REFDV_VALUE;         
  /* Configure PLL filter for optimal stability and lock time */
  REFDV_REFFRQ = REFFRQ_VALUE;        
  /* Set Postdiv value,  */
  POSTDIV_POSTDIV = POSTDIV_VALUE;                
  /* Configure VCO gain for optimal stability and lock time */
  SYNR_VCOFRQ = VCOFRQ_VALUE;         
  /* Clock Monitor Enable. This is required to enter Self Clock Mode */
  PLLCTL_CME = 1u;                     
  /* Self Clock Mode Enable, If CME & SCME are both asserted and the Clock Monitor
  in the oscillator block detects a loss of clock, Self Clock Mode will be entred */
  PLLCTL_SCME = 1u;                    
  /* Clear Self Clock Mode Interrupt Flag */                                                                          
  CRGFLG_SCMIF = 1u;                   
  /* Interrupt will be requested whenever SCMIF(Self Clock Mode Interrupt Flag) is set */ 
  CRGINT_SCMIE = 1u;
}

/*
** ===================================================================
**     Method      :  mcal_vPLL_ON(void)
**
**     Description :
**         Turns PLL ON.
** ===================================================================
*/
void mcal_vPLL_ON(void)
{            
  /* PLL enabled */
  PLLCTL_PLLON = 1u;                   
  
  /* Initialize PLL Loss-of-clock event counter */    
  mcal_mcu_u16PLL_Loss_of_Lock_Counter = 0u;            
  /* Wait until the PLL is within the desired frequency */
  while(!CRGFLG_LOCK)
  {}
  /* Initialize Global status variable to default value */                                   
  mcal_mcu_u16ClockGlobalStatus = CLOCK_STATUS_PLL_OK;        
  /* Clear IPLL Lock Interrupt Flag */
  CRGFLG_LOCKIF = 1u;                  
  /* Interrupt will be requested whenever LOCKIF(IPLL Lock Interrupt Flag)is set */        
  CRGINT_LOCKIE = 1u;                                                             
}

/*
** ===================================================================
**     Method      :  mcal_vPLL_OFF(void)
**
**     Description :
**         Turns PLL OFF.
** ===================================================================
*/
void mcal_vPLL_OFF(void)
{
  /* Disable the PLL */
  PLLCTL_PLLON = 0u;
  /* update global status variable */                                   
  mcal_mcu_u16ClockGlobalStatus = CLOCK_STATUS_PLL_OFF;
}

/*
** ===================================================================
**     Method      :  Mcu_vSelectClockSource_PLL(void)
**
**     Description :
**         Select PLL as clock source once it has been initialized.
** ===================================================================
*/
void Mcu_vSelectClockSource_PLL(void)
{
  /* Enable PLL and wait for locking */
  mcal_vPLL_ON();                          
  
  /* Once PLL is stable, select it as clock source */
  
  /* Select PLL as clock source */
  CLKSEL_PLLSEL = 1u;
  /* update global status variable */                                   
  mcal_mcu_u16ClockGlobalStatus = CLOCK_STATUS_PLL_SELECTED;
  /* update bus frequency variable with PLL frequency value */
  mcal_mcu_u32BusFrequency = ACTUAL_BUS_FREQ;    
}

/*
** ===================================================================
**     Method      :  Mcu_vSelectClockSource_XTAL(void)
**
**     Description :
**         Select XTAL as clock source at any time.
** ===================================================================
*/
void Mcu_vSelectClockSource_XTAL(void)
{
  /* Select XTAL as clock source */
  CLKSEL_PLLSEL = 0u;
  /* update global status variable */                                   
  mcal_mcu_u16ClockGlobalStatus = CLOCK_STATUS_XTAL_SELECTED;
  /* update bus frequency variable with XTAL frequency value */
  mcal_mcu_u32BusFrequency = ((UINT32)CNF_XTAL_FREQ_KHZ*1000u);    
}

/*
** ===================================================================
**     Method      :  Mcu_vPll_Clock_Monitor_Isr(void)
**
**     Description :
**         Clock Monitor Interrupt Service Routine.
** ===================================================================
*/
#pragma CODE_SEG __NEAR_SEG NON_BANKED
void interrupt Mcu_vPll_Clock_Monitor_Isr(void)
{    
  /* Verify that IPLL Lock Interrupt Flag caused the interrupt */
  if (CRGFLG_LOCKIF == 1u)
  {
    /* Clear IPLL Lock Interrupt Flag */  
    CRGFLG_LOCKIF = 1u;
    /* Update Loss-of-Lock event counter */
    mcal_mcu_u16PLL_Loss_of_Lock_Counter++;
    if (mcal_mcu_u16PLL_Loss_of_Lock_Counter >= 5u)
    {
      /* Set mcal_mcu_u16ClockGlobalStatus to its appropriate status */
      mcal_mcu_u16ClockGlobalStatus = CLOCK_STATUS_PLL_LOCK_ERROR;
      /* Configure all I/O to their default values */

      /* If we reach Loss-of-Lock 5 consecutive times, get into an infinite loop */
      for (;;){}
    }
  }
  else
  {        
    /* Verify that Self Clock Mode Interrupt flag caused the interrupt */
    if (CRGFLG_SCMIF == 1u)
    {
      /* Clear Self Clock Mode Interrupt Flag */
      CRGFLG_SCMIF = 1u;
      /* Set mcal_mcu_u16ClockGlobalStatus to its appropriate status */ 
      mcal_mcu_u16ClockGlobalStatus = CLOCK_STATUS_SCM_ERROR;        
      /* If we reach SCM condition, get into an infinite loop */
      for (;;){}                
    }
  } 
}
#pragma CODE_SEG DEFAULT
//
